/*
 * Copyright (c) 2009-2010, okazoh_tk. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *  - Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *  - Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *  - Neither the name of the copyright holder nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef ALKES_IRENDER_TARGET2D_H_INCLUDED_
#define ALKES_IRENDER_TARGET2D_H_INCLUDED_

#include "alkes/internal.h"
#include "alkes/core/ClassID.h"
#include "alkes/core/TRefCount.h"
#include "alkes/core/Types.h"
#include "alkes/media/Image.h"
#include "alkes/media/ImageWriter.h"
#include "alkes/gfx/StrokeStyle.h"

namespace alkes {

/// \addtogroup graphics
//@{

enum TargetBehavior
{
    AL_BEHAVIOR_DISCARD = 0x00,                 ///< Discard
    AL_BEHAVIOR_SINGLE  = 0x01,                 ///< Single buffer
    AL_BEHAVIOR_FLIP    = 0x10,
    AL_BEHAVIOR_DOUBLE = AL_BEHAVIOR_FLIP + 1,  ///< Double buffering
    AL_BEHAVIOR_TRIPLE,                         ///< Triple buffering
};

enum AlphaBlendMode
{
    AL_BLEND_ZERO = 0,      ///< (0,0,0,0)
    AL_BLEND_ONE,           ///< (1,1,1,1)
    AL_BLEND_SRCCOLOR,      ///< (Rs,Gs,Bs,As)
    AL_BLEND_INVSRCCOLOR,   ///< (1-Rs,1-Gs,1-Bs,1-As)
    AL_BLEND_DSTCOLOR,      ///< (Rd,Gd,Bd,Ad)
    AL_BLEND_INVDSTCOLOR,   ///< (1-Rd,1-Gd,1-Bd,1-Ad)
    AL_BLEND_SRCALPHA,      ///< (As,As,As,As)
    AL_BLEND_INVSRCALPHA,   ///< (1-As,1-As,1-As,1-As)
    AL_BLEND_DSTALPHA,      ///< (Ad,Ad,Ad,Ad)
    AL_BLEND_INVDSTALPHA,   ///< (1-Ad,1-Ad,1-Ad,1-Ad)
};

enum TexFilterValue
{
    AL_TEXFILTER_VALUE_POINT = 0,
    AL_TEXFILTER_VALUE_BILINEAR,
};

enum TexAddressMode
{
    AL_TEXADDRESS_MODE_DISABLE = 0,
    AL_TEXADDRESS_MODE_WRAP,
    AL_TEXADDRESS_MODE_CLAMP,
};

enum Graphics2DState
{
    AL_GS_ALPHA_BLEND = 0,  // alpha blend
    AL_GS_LINE_SMOOTH,      // Line antialias
    AL_GS_POLYGON_SMOOTH,   // Polygon antialias

    AL_GS_3D_STATE_BEGIN = 200, // for system
};

#define AL_OPACITY_MAX  (100)

class IGraphics2D;
class StrokeStyle;
class Shape;
class LineShape;
class RectangleShape;
class ImageShape;
class PolylineShape;

/** Rendering target interface for 2D object.
*/
class AL_EXPORT IRenderTarget2D
    : public TRefCount<IRenderTarget2D>
{
    AL_DECLARE_ROOT_CLASS(IRenderTarget2D);

public:

    /** Get owner of this object.

    @sa IGraphics2D
    */
    IGraphics2D* getIGraphics2D() const;

    bool correctTextureMapping() const;

    /** Take snapshot image.
    @param [in] writer Writer object.
    @param [in] rect 
    */
    void snapshot(
        ImageWriter& writer,
        const Rect* rect = 0);

    /** Get target behavior
    @return swap/flip behavior.
    @sa TargetBehavior
    */
    TargetBehavior getTargetBehavior() const;

    /** Begin to draw 2D.
    */
    virtual void beginDraw2D() = 0;

    /** Finish to draw 2D.
    */
    virtual void endDraw2D() = 0;

    /** Get rectangle of this target.
    @return Rectangle of this rendering target.
    */
    virtual const Rect getTargetRect() const = 0;

    /** Set scissor rectangle.
    @param [in] rect
    */
    virtual void setScissorRect(
        const Rect& rect) = 0;

    /** Get current scissor rectangle.
    @return current scissor rectangle.
    */
    virtual const Rect getScissorRect() = 0;

    /** Set rendering state.
    @param [in] state
    @param [in] enable
    */
    virtual void setState(int state, bool enable) = 0;

    /** Get rendering state.
    @param [in] state
    @retval true State is enable.
    @retval false State is disable.
    @sa Graphics2DState, Graphics3DState
    */
    virtual bool getState(int state) = 0;

    /** Set alpha blend mode.
    @param [in] src_blend New AlphaBlendMode of source.
    @param [in] dst_blend New AlphaBlendMode of destination.
    @sa AlphaBlendMode
    */
    virtual void setAlphaBlendMode(
        AlphaBlendMode src_blend,
        AlphaBlendMode dst_blend) = 0;

    /** Get alpha blend mode.

    @param [out] src_blend AlphaBlendMode of source.
    @param [out] dst_blend AlphaBlendMode of destination.
    @sa AlphaBlendMode
    */
    virtual void getAlphaBlendMode(
        AlphaBlendMode* src_blend,
        AlphaBlendMode* dst_blend) = 0;

    /** Set texture filter.
    @param [in] min_filter New TexFilterValue of min.
    @param [in] mag_filter New TexFilterValue of mag.
    @sa TexFilterValue
    */
    virtual void setTextureFilter(
        TexFilterValue min_filter,
        TexFilterValue mag_filter) = 0;

    /** Get texture filter.
    @param [out] min_filter TexFilterValue of min.
    @param [out] mag_filter TexFilterValue of mag.
    @sa TexFilterValue
    */
    virtual void getTextureFilter(
        TexFilterValue* min_filter,
        TexFilterValue* mag_filter) = 0;

    /** Set texture addressing.
    @param [in] u_mode New TexAddressMode of u coord.
    @param [in] v_mode New TexAddressMode of v coord.
    @sa TexAddressMode.
    */
    virtual void setTextureAddressMode(
        TexAddressMode u_mode,
        TexAddressMode v_mode) = 0;

    /** Get texture addressing.
    @param [out] u_mode New TexAddressMode of u coord.
    @param [out] v_mode New TexAddressMode of v coord.
    @sa TexAddressMode.
    */
    virtual void getTextureAddressMode(
        TexAddressMode* u_mode,
        TexAddressMode* v_mode) = 0;

    // rendering

    /** Fill this render target.
    @param [in] color
    @param [in] rect
    @retval true
    @retval false
    */
    virtual bool fill(
        const Color& color,
        const Rect* rect = 0) = 0;

    virtual bool drawShape(Shape* shape, uint32_t start = 0, uint32_t count = 1);
    virtual bool drawShape(LineShape* line_shape, uint32_t start = 0, uint32_t count = 1) = 0;
    virtual bool drawShape(RectangleShape* rectangle_shape, uint32_t start = 0, uint32_t count = 1) = 0;
    virtual bool drawShape(ImageShape* image_shape, uint32_t start = 0, uint32_t count = 1) = 0;
    virtual bool drawShape(PolylineShape* polyline_shape, uint32_t start = 0, uint32_t count = 1) = 0;

    // transforms
    virtual void pushMatrix() = 0;
    virtual void popMatrix() = 0;
    virtual void translate(const Vector2D& offset);
    virtual void translate(float x, float y) = 0;
    virtual void translateForImage(float x, float y);
    virtual void scale(float xscale, float yscale, const Vector2D& origin = Vector2D::ZERO) = 0;
    virtual void scale(float scaling, const Vector2D& origin = Vector2D::ZERO);
    virtual void rotate(float angle, const Vector2D& origin = Vector2D::ZERO) = 0;
    virtual void skewX(float angle) = 0;
    virtual void skewY(float angle) = 0;

protected:
    IRenderTarget2D(IGraphics2D* owner, TargetBehavior target_behavior);
    virtual ~IRenderTarget2D() = 0;

    friend class TRefCount<IRenderTarget2D>;
    virtual void destroy() = 0;

    virtual void onSnapshot(ImageWriter& writer, const Rect& rect) = 0;

private:
    IGraphics2D* owner_;
    TargetBehavior target_behavior_;
    int16_t opacity_;
};

//@}

}

#endif
